#include <stdlib.h>             // 标准头文件：size_t
#include <stdio.h>              // C/C++库：标准输入输出。printf();
#include <string.h>             // strcmp();
#include <unistd.h>             // C/C++对POSIX操作系统访问的API。sleep();

#include "ohos_init.h"          // SYS_RUN();
#include "ohos_types.h"         // bool
#include "cmsis_os2.h"          // osMessageQueuePut();
#include "hi_io.h"              // 海思hi3861SDK：HI_IO_NAME_GPIO_9

// iot_wifi
#include "button_control.h"
#include "iot_demo_def.h"
#include "iot_netcfg_nan.h"
#include "iot_nfc.h"
#include "iot_softap.h"
#include "iot_wifi.h"
#include "network_config_service.h"

#include "iot_watchdog.h"

// ADS1X15
#include "ADS1X15.h"

// SSD1306
#include "ssd1306.h"

// #include "netcfg.h"             // NetCfgRegister();
#include "oc_mqtt.h"            // device_info_init();
#include "gpio_control.h"
#include "wifi_connect.h"       // WifiConnect();

// extern g_wifi_status;
unsigned char   g_wifi_status =  CAR_WIFI_CONNECT_ING;

#define    SID_KEY        "ssid"
#define    PWD_KEY        "password"

#define    SOFTAP_NAME    "teamX-Lamp01"

// DEFAULT PARAM, AND MUST BE MODIFIED TO THE REAL PARAMS
#define CONFIG_CLOUD_DEFAULT_SERVERIP "121.36.42.100"    // replace it with iotplatform server ip
#define CONFIG_CLOUD_DEFAULT_SERVERPORT "1883"           // replace it with iotplatform server  port
#define CONFIG_SENSOR_SAMPLE_CYCLE 30000                  // unit:minisecond
#define CONFIG_TASK_DEFAULT_STACKSIZE 0x1000             // unit:bytes
#define CONFIG_TASK_DEFAULT_PRIOR 20                     // default task priority
#define CONFIG_TASK_MAIN_STACKSIZE 0x4000                // main task stacksize must be bigger
#define CONFIG_TASK_MAIN_PRIOR 25                        // default task priority
#define CONFIG_LOCAL_TIMEZONE            8
#define CONFIG_LED_DUTYCYCLEDEFAULT      20
#define CONFIG_LED_DUTYMAXMUN            99
#define CONFIG_LED_DUTYMINIMUM           1
#define CONFIG_FLASHLED_FRENETCONFIG     8
#define CONFIG_FLASHLED_FREWIFI          4
#define CONFIG_FLASHLED_FRECLOUD         1
#define CONFIG_FLASHLED_WORKSWELL        0.1

#define MSGQUEUE_OBJECTS 16     // 消息队列对象数量
osMessageQueueId_t mid_MsgQueue; // message queue id

#define CLIENT_ID "62687d6cb9f9fa4a4f9e3f17_OHOS_MPPT002_0_0_2022043007"
#define USERNAME "62687d6cb9f9fa4a4f9e3f17_OHOS_MPPT002"
#define PASSWORD "269bb5f12ef7c80bb33e6ebf2b34565472f2604d917a8395fd8fc27b2ba111d8"



// TODO:不符合鸿蒙编程规范
typedef enum
{
    en_msg_cmd = 0,
    en_msg_report,
} en_msg_type_t;

typedef struct
{
    char *request_id;
    char *payload;
} cmd_t;

/**
 * @brief 上报数据结构体
 * 
 */
typedef struct
{
    double involtage;
    double outvoltage;
    double incurrent;
    double outcurrent;
} report_t;

/**
 * @brief 消息队列数据结构体
 * 
 */
typedef struct
{
    en_msg_type_t msg_type;
    union
    {
        cmd_t cmd;
        report_t report;    // 上报数据
    } msg;
} app_msg_t;
typedef struct
{
    int connected;
    int led;
    int motor;
} app_cb_t;
static app_cb_t g_app_cb;

static bool g_netstatus = false;

#include <cJSON.h>
/**
 * @brief 1.下发命令执行函数
 * 
 * @param cmd 
 */
static void deal_cmd_msg(cmd_t *cmd)
{
    cJSON *obj_root;
    cJSON *obj_cmdname;
    cJSON *obj_paras;
    cJSON *obj_para;

    int cmdret = 1;
    oc_mqtt_profile_cmdresp_t cmdresp;
    obj_root = cJSON_Parse(cmd->payload);
    if (NULL == obj_root)
    {
        goto EXIT_JSONPARSE;
    }

    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (NULL == obj_cmdname)
    {
        goto EXIT_CMDOBJ;
    }
    if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Power"))    // 云端：服务=> 命令名称
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (NULL == obj_paras)
        {
            goto EXIT_OBJPARAS;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "Power");         // 云端：服务=> 下发参数
        if (NULL == obj_para)
        {
            goto EXIT_OBJPARA;
        }
        ///< operate the LED here
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.led = 1;
            // Light_StatusSet(ON);
            printf("Power On!");
        }
        else
        {
            g_app_cb.led = 0;
            // Light_StatusSet(OFF);
            printf("Power Off!");
        }
        cmdret = 0;
    }
    else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_Motor"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
        if (NULL == obj_paras)
        {
            goto EXIT_OBJPARAS;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "Motor");
        if (NULL == obj_para)
        {
            goto EXIT_OBJPARA;
        }
        ///< operate the Motor here
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.motor = 1;
            // Motor_StatusSet(ON);
            printf("Motor On!");
        }
        else
        {
            g_app_cb.motor = 0;
            // Motor_StatusSet(OFF);
            printf("Motor Off!");
        }
        cmdret = 0;
    }

EXIT_OBJPARA:
EXIT_OBJPARAS:
EXIT_CMDOBJ:
    cJSON_Delete(obj_root);
EXIT_JSONPARSE:
    ///< do the response
    cmdresp.paras = NULL;
    cmdresp.request_id = cmd->request_id;
    cmdresp.ret_code = cmdret;
    cmdresp.ret_name = NULL;
    (void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
    return;
}

/**
 * @brief 2.数据上报函数
 * 
 * @param report 
 */

static void deal_report_msg(report_t *report)
{
    oc_mqtt_profile_response_t response;
    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t InVoltage;
    oc_mqtt_profile_kv_t OutVoltage;
    oc_mqtt_profile_kv_t InCurrent;
    oc_mqtt_profile_kv_t OutCurrent;
    // oc_mqtt_profile_kv_t led;
    // oc_mqtt_profile_kv_t motor;

    // 对JSON数据进行拼装。
    response.response = &service;

    service.event_time = NULL;
    service.service_id = "Solar";                       // 云端服务ID
    service.service_property = &InVoltage;
    service.nxt = NULL;

    InVoltage.key = "InVoltage";                        // 云端：服务=> 属性名称
    InVoltage.value = &report->involtage;
    InVoltage.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;    // 注意：如果上报类型为FLOAT，数据采集时要使用double类型，否则会导致数据错误
    InVoltage.nxt = &OutVoltage;
    printf("========%s",InVoltage.value);
            //ScreenPrintf(0, 10,InVoltage.value);

    OutVoltage.key = "OutVoltage";
    OutVoltage.value = &report->outvoltage;
    OutVoltage.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;
    OutVoltage.nxt = &InCurrent;

    InCurrent.key = "InCurrent";
    InCurrent.value = &report->incurrent;
    InCurrent.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;
    InCurrent.nxt = &OutCurrent;

    OutCurrent.key = "OutCurrent";
    OutCurrent.value = &report->outcurrent;
    OutCurrent.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;
    OutCurrent.nxt = NULL;

    // motor.key = "MotorStatus";
    // motor.value = g_app_cb.motor ? "ON" : "OFF";
    // motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    // motor.nxt = NULL;

    //report data is {"services":[{"service_id":"Solar","properties":{"InVoltage":1.5299999713897706,"OutVoltage":0.41249999403953553,"InCurrent":2.4733126163482667,"OutCurrent":0.93000000715255738}}]}
    oc_mqtt_profile_propertyreport(USERNAME, &service); // 调用API进行数据上报
    return;
}

/**
 * @brief 获取到云端命令的回调函数
 * 
 * @param recv_data 
 * @param recv_size 
 * @param resp_data 
 * @param resp_size 
 */
void oc_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size)
{
    app_msg_t *app_msg;

    int ret = 0;
    app_msg = malloc(sizeof(app_msg_t));
    app_msg->msg_type = en_msg_cmd;                 // 设置消息类型为：下发命令
    app_msg->msg.cmd.payload = (char *)recv_data;

    printf("recv data is %.*s\n", recv_size, recv_data);
    //recv data is {"paras":{"Power":"OFF"},"service_id":"Solar","command_name":"Power"} 下发命令
    //recv data is {"paras":{"result":"NO"},"service_id":"Solar","command_name":"Power"} 下发命令

    ret = osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U);    // 将获取到的信息添加到消息队列
    if (ret != 0)
    {
        free(recv_data);
    }
    *resp_data = NULL;
    *resp_size = 0;
}

/**
 * @brief 2.传感器信息采集任务
 * 
 * @return int 
 */
static int task_sensor_entry(void)
{

    OperatingData operatingData;
    SystemState systemState;                // 系统状态
    PredictiveBuckDuty(&operatingData);    // 预测Buck占空比
    // InitGpio();
    int i = 0;
    while (1)
    {
        systemState = GetState(&operatingData);          // 获取设备运行状态数据
        if (systemState.errCount == 0)
        {
            printf("系统正常运行,执行MPPT\n");
            ScreenPrintf(0, 0,"State:MPPT RUN");
            SystemControl(true);
            MpptAlgorithm(&operatingData);     // 通过运行数据计算MPPT        
        }else
        {
            printf("系统异常,关闭系统\n");
            ScreenPrintf(0, 0,"System Closed!");
            SystemControl(false);
            BuckPwmControl(false,99);              // 设置Buck电路占空比
        }
        
        


        if (i == 60000) //每60S上报一次数据
        {
            /* 上报数据 */
            app_msg_t *app_msg;
            app_msg = malloc(sizeof(app_msg_t));

            if (NULL != app_msg)
            {
                app_msg->msg_type = en_msg_report;                              // 设置消息类型为：上报数据
                app_msg->msg.report.involtage = operatingData.involtage;
                app_msg->msg.report.outvoltage = operatingData.outvoltage;
                app_msg->msg.report.incurrent = operatingData.incurrent;
                app_msg->msg.report.outcurrent = operatingData.outcurrent;

                if (0 != osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U))     //将要发送的信息添加到消息队列
                {
                    free(app_msg);
                }
            }
            i=0;
        }
        i++;
        usleep(100);
    }
    return 0;
}

/**
 * @brief 1.初始化任务，连接wifi，华为云，处理消息队列消息
 * 
 * @return int 
 */
static int task_main_entry(void){

    device_info_init(CLIENT_ID, USERNAME, PASSWORD);    // 配置设备信息
    oc_mqtt_init();                                     // oc mqtt 客户端的初始化
    oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);                   // 设置命令响应的回调函数

    app_msg_t *app_msg;

    while (1)
    {
        app_msg = NULL;
        (void)osMessageQueueGet(mid_MsgQueue, (void **)&app_msg, NULL, 0U);   // 持续获取队列中的消息
        if (NULL != app_msg)
        {
            switch (app_msg->msg_type)
            {
            case en_msg_cmd:                        // 队列中的消息类型：下发命令
                printf("下发命令\n");    //test
                deal_cmd_msg(&app_msg->msg.cmd);
                break;
            case en_msg_report:                     // 队列中的消息类型：上报数据
                printf("上报数据\n");    //test
                deal_report_msg(&app_msg->msg.report);
                break;
            default:
                printf("未知的消息类型\n");    //test
                break;
            }
            free(app_msg);
        }
    }
    return 0;    
}

static void Main_Entry(void)
{
    mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, 10, NULL);   // 新建一个消息队列
    if (mid_MsgQueue == NULL)
    {
        printf("Falied to create Message Queue!\n");
    }

    osThreadAttr_t attr;

    attr.name = "task_main_entry";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = 24;

    if (osThreadNew((osThreadFunc_t)task_main_entry, NULL, &attr) == NULL)      // 1.初始化任务，连接wifi，华为云，处理消息队列消息
    {
        printf("Falied to create task_main_entry!\n");
    }
    attr.stack_size = 2048;
    attr.priority = 25;
    attr.name = "task_sensor_entry";
    if (osThreadNew((osThreadFunc_t)task_sensor_entry, NULL, &attr) == NULL)    // 2.传感器信息采集任务
    {
        printf("Falied to create task_sensor_entry!\n");
    }
}

static int NetEventHandler(NET_EVENT_TYPE event, void *data)
{
    switch (event) {
        case NET_EVENT_CONNECTTED:                                      // 网络连接成功
            g_netstatus = true;
            Main_Entry();
            break;
        case NET_EVENT_RECV_DATA:                                       // 接收到网络信息(FA发送的消息)
            // WinderProcessAppMessage((const char *)data, strlen(data));  // 处理对应的信息
            break;
        default:
            break;
    }
    return 0;
}

static void NetcfgMain(){
    NfcInfo nfcInfo;
    // (void)arg;
    char ssid[BUFF_SIZE] = {0};
    char pwd[BUFF_SIZE] = {0};
    int ret;

    nfcInfo.deviceID = "62687d6cb9f9fa4a4f9e3f17_OHOS_MPPT002";
    nfcInfo.devicePWD = "12345678";

    g_wifi_status = CAR_WIFI_CONNECT_ING;
    ssd1306_SetCursor(5, 40);
    ssd1306_DrawString("WIFI connecting", Font_7x10, White);
    ssd1306_UpdateScreen();

    //
    // ret=get_gpio5_voltage();
    // RaiseLog(LOG_LEVEL_ERR, "get_gpio5_voltage->%d", ret);
    // if (ret)
    // {
        // RaiseLog(LOG_LEVEL_INFO, "Netconfig Button has pressed! \n");
        if(BOARD_NAN_NetCfgStartConfig(SOFTAP_NAME, ssid, sizeof(ssid), pwd, sizeof(pwd)) < 0)  // 开始网络配置。如果成功返回 ssid 和 pwd。开始配网会循环 wait STA join AP
        {
            RaiseLog(LOG_LEVEL_ERR, "BOARD_NetCfgStartConfig failed! \n");
            return;
        }
        ret = 0;
    // }
    // else
    // {
    //     ret = IotWifiInfo_get(ssid, sizeof(ssid), pwd, sizeof(pwd));
    //     if (ret == 0)
    //     {
    //         if(BOARD_NAN_NetCfgStartConfig(SOFTAP_NAME, ssid, sizeof(ssid), pwd, sizeof(pwd)) < 0)
    //         {
    //             RaiseLog(LOG_LEVEL_ERR, "BOARD_NetCfgStartConfig failed! \n");
    //             return;
    //         }
    //     }
    // }
    
    if (BOARD_ConnectWifi(ssid, pwd) != 0)                         // 连接wifi，本质调用的WifiConnect()，由iot_wifi/iot_wifi.c实现
    {
        RaiseLog(LOG_LEVEL_ERR, "BOARD_ConnectWifi failed! \n");
        NotifyNetCfgResult(NETCFG_DEV_INFO_INVALID);
        // hi_hard_reboot(HI_SYS_REBOOT_CAUSE_CMD);
        hi_hard_reboot(1);
        return;
    }
    g_wifi_status = CAR_WIFI_CONNECT_OK;
    ssd1306_SetCursor(5, 40);
    ssd1306_DrawString("WIFI connect ok", Font_7x10, White);
    ssd1306_UpdateScreen();


    // if (ret == 0)                                                    // 前面已经连接wifi了，这里不需要了
    // {
    //     RaiseLog(LOG_LEVEL_DEBUG, "Connect wifi success ! \n");
    //     NotifyNetCfgResult(NETCFG_OK);
    //     osDelay(100);
    //     RaiseLog(LOG_LEVEL_DEBUG, "StopNetCfg wifi success ! \n");

    //     /* libnetcfgdevicesdk.a下的API函数StopNetCfg */
    //     StopNetCfg();


    //     // IotWifiInfo_set(ssid, pwd);
    //     // printf("ssid:%s,pwd:%s\n",ssid, pwd);
    //     // int ret = WifiConnect("HUAWEI-SRVS2T_HiLink", "147258369");
    //     // if(WifiConnect(ssid,pwd) == 0){
    //     //     printf("wifi connect seccess\n");
    //     // }else{
    //     //     printf("wifi connect failed\n");
    //     // }
    // }

    //  正常应该在网路连接成功后，触发NetEventHandler(),但是没有，所以手动启动Main_Entry();
    Main_Entry();

    // 接入云端
    // if (CLOUD_Init() != 0)
    // {
    //     return;
    // }else
    // {
    //     RaiseLog(LOG_LEVEL_DEBUG, "CLOUD_Init() success ! \n");
    // }
    // if (CLOUD_Connect(nfcInfo.deviceID, nfcInfo.devicePWD,
    //                   CONFIG_CLOUD_DEFAULT_SERVERIP, CONFIG_CLOUD_DEFAULT_SERVERPORT) != 0)
    // {
    //     return;
    // }
    // g_wifi_status = CAR_IOT_CONNECT_OK;




    // attr.attr_bits = 0U;
    // attr.cb_mem = NULL;
    // attr.cb_size = 0U;
    // attr.stack_mem = NULL;
    // attr.stack_size = CONFIG_TASK_DEFAULT_STACKSIZE;
    // attr.priority = CONFIG_TASK_DEFAULT_PRIOR;
    // attr.name = "DataCollectAndReport";

    // (void)osThreadNew((osThreadFunc_t)SensorTaskEntry, NULL, (const osThreadAttr_t *)&attr);
    return;
}

/* MAX:ScreenPrintf(0, 51,"012345678876543210"); */
void ScreenPrintf(int x,int y,char* message){
    ssd1306_SetCursor(x, y);
    ssd1306_DrawString(message, Font_7x10, White);
    ssd1306_UpdateScreen();
}

static void SystemInit(){

    IoTWatchDogDisable();   // 关闭看门狗,  否则60s设备会重启
    printf("test\n");

    /*添加显示屏*/
    usleep(20*1000);
    InitGpio();
    ssd1306_Init();
    ssd1306_Fill(Black);
    // ScreenPrintf(60, 0,"|");
    // ScreenPrintf(60, 10,"|");
    // ScreenPrintf(60, 20,"|");
    // ScreenPrintf(60, 30,"|");
    // ScreenPrintf(60, 40,"|");
    // ScreenPrintf(60, 50,"|");
    //ScreenPrintf(0, 50,"012345678876543210");
    ssd1306_SetCursor(5, 10);
    ssd1306_DrawString("OpenHarmony", Font_11x18, White);
    ssd1306_UpdateScreen();
    /*添加显示屏*/







    PwmInit();
    // BuckPwmControl(true,50);              // 设置Buck电路占空比
    //Main_Entry();//为了方便测试先跳过配网，使用指定SSID



    /**
     * @brief 3.0、3.1 智能保险柜配网代码，包含iot_wifi文件件内容
     * 北向是NaN+SoftAP配网，效果好，已经移植到3.0。
     * https://gitee.com/openharmony-sig/knowledge_demo_smart_home/blob/master/docs/smart_safe/README.md
     */
    NetcfgMain();
}

SYS_RUN(SystemInit);